﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Glue;
using Xunit;

namespace GlueTests.MapperTests
{
    public class When_mapping_between_different_types_of_enumerables
    {
        private readonly Mapping<FromPerson, ToPerson> mapping;
        private readonly FromPerson fromPerson;

        public class FromPerson
        {
            public List<int> List { get; set; }
            public IList<int> IList { get; set; }
            public ICollection<int> ICollection { get; set; }
            public IEnumerable<int> IEnumerable { get; set; }
            public int[] Array { get; set; }
        }

        public class ToPerson
        {
            public List<int> List { get; set; }
            public IList<int> IList { get; set; }
            public ICollection<int> ICollection { get; set; }
            public IEnumerable<int> IEnumerable { get; set; }
            public int[] Array { get; set; }
        }

        public When_mapping_between_different_types_of_enumerables()
        {
            mapping = new Mapping<FromPerson, ToPerson>();

            fromPerson = new FromPerson
                 {
                     List = new List<int> {1, 2, 3, 4},
                     IList = new List<int> {1, 2, 3, 4},
                     ICollection = new List<int> {1, 2, 3, 4},
                     IEnumerable = new List<int> {1, 2, 3, 4},
                     Array = new[] {1, 2, 3, 4}

                };
        }

        [Fact]
        public void Should_map_between_List_and_IList()
        {
            Assert(x => x.List, y => y.IList);
        }

        [Fact]
        public void Should_map_between_List_and_ICollection()
        {
            Assert(x => x.List, y => y.ICollection);
        }

        [Fact]
        public void Should_map_between_List_and_IEnumerable()
        {
            Assert(x => x.List, y => y.IEnumerable);
        }

        [Fact]
        public void Should_map_between_List_and_Array()
        {
            Assert(x => x.List, y => y.Array);
        }

        [Fact]
        public void Should_map_between_IList_and_ICollection()
        {
            Assert(x => x.IList, y => y.ICollection);
        }

        [Fact]
        public void Should_map_between_IList_and_IEnumerable()
        {
            Assert(x => x.IList, y => y.IEnumerable);
        }

        [Fact]
        public void Should_map_between_IList_and_Array()
        {
            Assert(x => x.IList, y => y.Array);
        }


        [Fact]
        public void Should_map_between_ICollection_and_IEnumerable()
        {
            Assert(x => x.ICollection, y => y.IEnumerable);
        }

        [Fact]
        public void Should_map_between_ICollection_and_Array()
        {
            Assert(x => x.ICollection, y => y.Array);
        }

        [Fact]
        public void Should_map_between_IEnumerable_and_Array()
        {
            Assert(x => x.IEnumerable, y => y.Array);
        }

        private void Assert(Expression<Func<FromPerson,object>> fromProperty, Expression<Func<ToPerson,object>> toProperty)
        {
            mapping.Relate(fromProperty, toProperty);
            var toPerson = mapping.Map(fromPerson, new ToPerson());
            When_mapping_Between_Enumerables.AssertEqual(
                (IEnumerable<int>)fromProperty.Compile().Invoke(fromPerson), 
                (IEnumerable<int>)toProperty.Compile().Invoke(toPerson));
        }
    }
}
